#include "memory_object_pool.h"


MemoryObject::MemoryObject(MemoryObject &&other) {
    m_buffer.swap(other.m_buffer);
    m_usedSize = other.m_usedSize;
}

bool MemoryObject::fill(unsigned char *data, size_t size, size_t offset) {
    if(offset + size > totalSize())
        return false;
    memcpy(m_buffer.data()+offset, data, size);
    m_usedSize = offset + size;
    return true;
}

MemoryObjectPool::MemoryObjectPool(size_t count, size_t size, size_t maxCount) : m_maxCount(maxCount)
{
    for(int i = 0; i < count; i++) {
        m_pool.emplace_back(MemoryObjectPool::create(size));
    }
}

std::unique_ptr<MemoryObject> MemoryObjectPool::create(size_t size)
{
    return std::make_unique<MemoryObject>(size);
}

MemoryObjectPool &MemoryObjectPool::instance()
{
    static MemoryObjectPool pool;
    return pool;
}

std::unique_ptr<MemoryObject> MemoryObjectPool::take(size_t leastSize)
{
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        for(auto iter = m_pool.begin(); iter != m_pool.end(); iter++) {
            if((*iter)->totalSize() >= leastSize) {
                auto tmp = std::move(*iter);
                if(tmp->usedSize() > 0)
                    tmp->setUsedSize(0);
                m_pool.erase(iter);
                return tmp;
            }
        }
    }
    return MemoryObjectPool::create(leastSize);
}

void MemoryObjectPool::give(std::unique_ptr<MemoryObject> &&mo)
{
    std::lock_guard<std::mutex> lock(m_mutex);
    m_pool.emplace_front(std::move(mo));
    while(m_pool.size() > m_maxCount)
        m_pool.pop_back();
}

